﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

namespace Framework
{
    public sealed class SingleUIImageCache : Singleton<SingleUIImageCache>
    {
        sealed class UIImageCacheItem
        {
            internal AssetItem assetItem;
            internal string resPath;
            internal Sprite sprite;
            internal readonly List<Image> imageComps;
            internal SpriteMeshType spriteMeshType;

            internal UIImageCacheItem(string resPath, SpriteMeshType spriteMeshType)
            {
                this.resPath = resPath;
                imageComps = new List<Image>();
                this.spriteMeshType = spriteMeshType;
            }
        }

        private readonly Dictionary<string, UIImageCacheItem> _allCacheItems = new Dictionary<string, UIImageCacheItem>();
        private readonly Dictionary<Image, UIImageCacheItem> _useMarks = new Dictionary<Image, UIImageCacheItem>();
        private readonly Dictionary<Image, Action<float, float>> _loadedCbCache = new Dictionary<Image, Action<float, float>>();

        public void SetImageSprite(Image image, SpriteMeshType spriteMeshType, string resPath, Action<float, float> loadedCb = null)
        {
            resPath = FileHelper.GetUnityPath(resPath);
            if (null == image || string.IsNullOrEmpty(resPath))
            {
                if (null != image)
                {
                    Logger.LogError("SingleUIImageCache.SetImageSprite, resPath can not be null! image = " + GameObjectHelper.GetPath(image.gameObject));
                }
                else if (!string.IsNullOrEmpty(resPath))
                {
                    Logger.LogError("SingleUIImageCache.SetImageSprite, image can not be null! resPath = " + resPath);
                }
                else
                {
                    Logger.LogError("SingleUIImageCache.SetImageSprite, image and resPath can not be null!");
                }
                return;
            }
            //清理使用记录
            if (_useMarks.TryGetValue(image, out UIImageCacheItem imageCacheItem))
            {
                if (resPath.Equals(imageCacheItem.resPath))
                {
                    return;
                }
                imageCacheItem.imageComps.Remove(image);
                _useMarks.Remove(image);
                _loadedCbCache.Remove(image);
            }
            imageCacheItem = null;
            if (image.sprite == null)
            {
                //加载图之前不显示Image，避免白块
                image.enabled = false;
            }
            //重新赋值sprite
            if (_allCacheItems.TryGetValue(resPath, out imageCacheItem))
            {
                imageCacheItem.imageComps.Add(image);
                _useMarks.Add(image, imageCacheItem);
                if (null != imageCacheItem.assetItem)
                {
                    image.sprite = imageCacheItem.sprite;
                    image.enabled = true;
                    if (null != loadedCb)
                    {
                        float width = imageCacheItem.sprite.texture.width;
                        float height = imageCacheItem.sprite.texture.height;
                        loadedCb(width, height);
                    }
                }
                else
                {
                    if (null != loadedCb)
                    {
                        _loadedCbCache.Add(image, loadedCb);
                    }
                }
                return;
            }
            imageCacheItem = new UIImageCacheItem(resPath, spriteMeshType);
            imageCacheItem.imageComps.Add(image);
            _useMarks.Add(image, imageCacheItem);
            if (null != loadedCb)
            {
                _loadedCbCache.Add(image, loadedCb);
            }
            _allCacheItems.Add(resPath, imageCacheItem);
            StartLoadTextureAb(resPath);
        }
        /// <summary>
        /// 正在加载的公共ab名字
        /// </summary>
        private HashSet<string> abPathesInLoading = new HashSet<string>();
        /// <summary>
        /// 开始加载sprite用到的图片ab
        /// </summary>
        /// <param name="resPath"></param>
        private void StartLoadTextureAb(string resPath)
        {
            // if (ResMgr.Instance.IsFromEditorDir || !ResMgr.IsSingleBg(resPath))
            if (ResMgr.Instance.IsFromEditorDir)
            {
                ResMgr.Instance.GetAbAsset(resPath, false, OnImageResLoaded);
                return;
            }
            // string abPath = ResMgr.Instance.GetSingleBgAbPath(resPath);
            string abPath = resPath;
            if (abPathesInLoading.Contains(abPath))
            {
                return;
            }
            abPathesInLoading.Add(abPath);
            ResMgr.Instance.GetAbAsset(resPath, false, OnImageResLoaded);
        }

        private void OnImageResLoaded(AssetItem assetItem)
        {
            if (assetItem.IsLoadSuccess)
            {
                //如果不是singlebg目录下的图或者ab,或者是编辑器直接加载模式
                // if (!ResMgr.IsSingleBg(assetItem.ResPath) || ResMgr.Instance.IsFromEditorDir)
                if (ResMgr.Instance.IsFromEditorDir)
                {
                    if (!_allCacheItems.TryGetValue(assetItem.ResPath, out UIImageCacheItem imageCacheItem))
                    {
                        return;
                    }
                    imageCacheItem.assetItem = assetItem;
                    assetItem.Retain();
                    ApplySprite(assetItem, imageCacheItem, null);
                    return;
                }
                abPathesInLoading.Remove(assetItem.ResPath);
                //singlebg目录下的ab，则刷新这个ab中包含图片的所有UIIMageCacheItem
                // Logger.Log($"assetItem.ResPath = {assetItem.ResPath}");
                // var assetNames = ResMgr.Instance.GetAssetNamesInSingleBgAb(assetItem.ResPath + FrameworkSettings.DataExt);
                var assetNames = new []{assetItem.ResPath + FrameworkSettings.DataExt};
                foreach (var assetName in assetNames)
                {
                    string resPath = assetName.Replace("Assets/" + FrameworkSettings.ResourcesLibName + "/", "");
                    // Logger.Log($"resPath = {resPath} assetName = {assetName}");
                    if (!_allCacheItems.TryGetValue(resPath, out UIImageCacheItem imageCacheItem))
                    {
                        continue;
                    }

                    imageCacheItem.assetItem = assetItem;
                    assetItem.Retain();
                    ApplySprite(assetItem, imageCacheItem, resPath);
                }
            }
        }

        /// <summary>
        /// 使用Texture2D给创建sprite应用到组件上
        /// </summary>
        /// <param name="assetItem"></param>
        /// <param name="imageCacheItem"></param>
        /// <param name="resPath"></param>
        private void ApplySprite(AssetItem assetItem, UIImageCacheItem imageCacheItem, string resPath)
        {
            Texture2D texture2D = assetItem.GetResource(resPath) as Texture2D;
            imageCacheItem.sprite = Sprite.Create(texture2D, new Rect(0, 0, texture2D.width, texture2D.height),
                new Vector2(0, 0), 100f, 0, imageCacheItem.spriteMeshType);

            for (int idx = imageCacheItem.imageComps.Count - 1; idx >= 0; idx--)
            {
                var image = imageCacheItem.imageComps[idx];
                image.sprite = imageCacheItem.sprite;
                image.enabled = true;
                if (_loadedCbCache.TryGetValue(image, out System.Action<float, float> loadedCb))
                {
                    loadedCb(texture2D.width, texture2D.height);
                    _loadedCbCache.Remove(image);
                }
            }
        }

        public void RemoveImageSprite(Image image)
        {
            image.enabled = false;
            image.overrideSprite = null;
            image.sprite = null;

            if (_useMarks.TryGetValue(image, out UIImageCacheItem imageCacheItem))
            {
                imageCacheItem.imageComps.Remove(image);
                _useMarks.Remove(image);
                _loadedCbCache.Remove(image);
            }
        }

        public void UnloadUnusedRes()
        {
            UIImageCacheItem cacheItem = null;
            List<string> toBeRemoveKey = new List<string>();
            foreach (var kvp in _allCacheItems)
            {
                cacheItem = kvp.Value;
                if (0 != cacheItem.imageComps.Count)
                {
                    continue;
                }
                toBeRemoveKey.Add(kvp.Key);
                if (null == cacheItem.assetItem)
                {
                    ResMgr.Instance.RemoveAssetItemCb(kvp.Key, OnImageResLoaded);
                    //2024.02.22 1.6包体问题 第6章章节图片加载不了，如果图片还没加载完，就调用到这里，abPathesInLoading没清掉path，导致下次无法正常加载
                    // if (!ResMgr.Instance.IsFromEditorDir && ResMgr.IsSingleBg(cacheItem.resPath))
                    if (!ResMgr.Instance.IsFromEditorDir)
                    {
                        // string abPath = ResMgr.Instance.GetSingleBgAbPath(cacheItem.resPath);
                        string abPath = (cacheItem.resPath);
                        if (abPath != null)
                        {
                            abPathesInLoading.Remove(abPath);
                        }
                    }
                    continue;
                }
                cacheItem.assetItem.Release();
                cacheItem.assetItem = null;
                UnityEngine.Object.Destroy(cacheItem.sprite);
                //卸载掉不用的图片资源
                //2024.02.22 1.6包体问题 未锈铠卡池图片丢失，这里不能卸掉，其他地方使用非SingleImage的加载方式加载图片，Texture会丢失
                //UnityEngine.Resources.UnloadAsset(cacheItem.sprite.texture);
                cacheItem.sprite = null;
                cacheItem.resPath = null;
            }

            foreach (var key in toBeRemoveKey)
            {
                _allCacheItems.Remove(key);
            }
        }
    }
}

